﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using System.Xml;
using TreeNode=System.Windows.Forms.TreeNode;
using FileModelNS;

namespace StructureTree
{
    public partial class StructureTree : UserControl
    {
    	private FileModel _FileModel;

        public StructureTree()
        {
            InitializeComponent();
        }

		public void SetFileModel(FileModel fileModel)
		{
			if (null == fileModel) throw new Exception("Invalid Argument");
			if (null != _FileModel) throw new Exception("FileModel Already Exists");

			_FileModel = fileModel;
			fileModel.FormatLoaded += new EventHandler(FileModel_FormatLoaded);
			fileModel.FormatUnloaded += new EventHandler(FileModel_FormatUnloaded);
			fileModel.SelectedFormatNodeChanged += new EventHandler(FileModel_SelectedFormatNodeChanged);
		}

		private void FileModel_FormatLoaded(object sender, EventArgs e )
		{
			Debug.Assert(_FileModel == sender);

			try
			{
				FileModel fileModel = (FileModel)sender;
				var modelRootNode = fileModel.Tree.RootNodes[0];


				// SECTION 1. Initialize the TreeView control.
				//
				treeView.Nodes.Clear();
				var viewRootNode = new TreeNode(modelRootNode.Value.Text);
				viewRootNode.Tag = modelRootNode.Value;
				treeView.Nodes.Add(viewRootNode);

				// SECTION 2. Populate the TreeView with the Rree nodes.
				//
				AddNode(viewRootNode, modelRootNode);
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
				treeView.Nodes.Clear();
			}
		}

        private void AddNode(TreeNode inViewNode, TreeNode<FormatNode> inModelNode )
        {
        	if (inModelNode.ChildNodes.Count != 0)
        	{
        		foreach (var curModelNode in inModelNode.ChildNodes)
        		{
					// Add new TreeNode into the Tree
        			var curViewNode = new TreeNode(
        				curModelNode.Value.Text,
        				(curModelNode.ChildNodes.Count == 0) ? 2 : 0,
        				(curModelNode.ChildNodes.Count == 0) ? 2 : 0);
        			curViewNode.Tag = curModelNode.Value;
        			inViewNode.Nodes.Add(curViewNode);

        			// Recursive!
        			AddNode(curViewNode, curModelNode);
        		}
        	}
        }

		private void FileModel_FormatUnloaded(object sender, EventArgs e)
		{
			Debug.Assert(_FileModel == sender);
			treeView.Nodes.Clear();
		}
		
		private void SetToolTip(TreeNode treeNode)
        {
            var fnode = (FormatNode)treeNode.Tag;
            treeNode.ToolTipText = "full name: " + fnode.Text + "\nsize: " + fnode.Size + "\noffset: " + fnode.Offset + "\ncomment: " + fnode.Comment;
        }

        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
        	Debug.Assert(treeView.SelectedNode == e.Node);
            FormatNode formatNode = (FormatNode)e.Node.Tag;
			_FileModel.SelectFormatNode( formatNode.Path );
        }

		private void FileModel_SelectedFormatNodeChanged(object sender, EventArgs e )
		{
			Debug.Assert(_FileModel == sender);

			// Check if already selected.
			if ( treeView.SelectedNode != null &&
				treeView.SelectedNode.Tag == _FileModel.SelectedFormatNode)
				return;

			var treeNode = FindTreeNode( treeView.Nodes[0], _FileModel.SelectedFormatNode);
			Debug.Assert(null != treeNode);
			if ( null != treeNode )
			{
				treeView.SelectedNode = treeNode;
			}
		}

		/// <summary>
		/// Find a tree node that its Tag is formatNode.
		/// </summary>
		/// <param name="treeNode">Root node of sub tree in which we find a tree node.</param>
		/// <param name="formatNode">Format node to find</param>
		/// <returns></returns>
		private TreeNode FindTreeNode( TreeNode treeNode, FormatNode formatNode)
		{
			if (treeNode.Tag == formatNode)
				return treeNode;

			foreach( TreeNode childNode in treeNode.Nodes )
			{
				var nodeFound = FindTreeNode(childNode, formatNode);
				if (null != nodeFound)
					return nodeFound;
			}
			return null;
		}
		
    }
}
 